import socket
import re
import time
from datetime import datetime
from urllib.parse import urlparse
import paramiko
from config.settings import get_config
from base.base_page import BasePage

class Get_Local_Ip(BasePage):
    def __init__(self, driver, device_type, logger=None):
        super().__init__(driver, device_type, logger=logger)
        self.driver = driver
        self.config = get_config(device_type)

    def get_local_ip(self, get_all=False):
        """
        获取本机所有有效IPv4地址（排除回环地址）

        参数：
            get_all (bool): 是否返回全部地址列表，默认False返回第一个有效地址

        返回：
            str/list/None: 单个IP字符串或IP列表，无有效地址时返回None
        """
        ip_list = []

        # 方法1：通过UDP连接外部地址获取出口IP（推荐）
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
                s.connect(('8.8.8.8', 80))  # 连接Google DNS
                ip_list.append(s.getsockname()[0])
        except (OSError, socket.error):
            pass

        # 方法2：通过主机名解析获取所有IP
        try:
            host_info = socket.gethostbyname_ex(socket.gethostname())[2]
            ip_list.extend(
                ip for ip in host_info
                if ip != '127.0.0.1' and ip not in ip_list
            )
        except (socket.gaierror, socket.error):
            pass

        # 方法3：遍历所有网络接口（兼容复杂网络环境）
        try:
            for interface in socket.getaddrinfo(socket.gethostname(), None):
                if interface[0] == socket.AF_INET:
                    ip = interface[4][0]
                    if ip not in ip_list and ip != '127.0.0.1':
                        ip_list.append(ip)
        except (socket.gaierror, socket.error):
            pass

        if not ip_list:
            return None if not get_all else []

        return ip_list if get_all else ip_list[0]

    def get_cron_hour(self, base_url):
        """
        从指定URL提取IP，通过SSH检查定时任务，返回目标cron任务的小时数

        参数:
            base_url (str): 包含目标IP的URL（如 https://10.4.0.204:7443/login）

        返回:
            tuple: (结果, 错误信息)
            成功示例: (9, None)
            失败示例: (None, "SSH连接失败: Authentication failed")
        """
        # 解析URL获取IP
        try:
            parsed_url = urlparse(base_url)
            ip = parsed_url.hostname
            if not ip or not re.match(r"\d+\.\d+\.\d+\.\d+", ip):
                return None, "无效的IP地址"
        except Exception as e:
            return None, f"URL解析失败: {str(e)}"

        # SSH连接配置
        ssh_config = {
            "hostname": ip,
            "port": 22,  # 默认SSH端口
            "username": "root",
            "password": "Guoyu@657",
            "timeout": 10
        }

        # 执行SSH命令
        try:
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            client.connect(**ssh_config)

            # 获取crontab内容
            stdin, stdout, stderr = client.exec_command("crontab -l")
            exit_status = stdout.channel.recv_exit_status()

            if exit_status != 0:
                error = stderr.read().decode().strip()
                return None, f"命令执行失败 (code:{exit_status}): {error}"

            cron_content = stdout.read().decode()
        except paramiko.AuthenticationException:
            return None, "SSH认证失败（密码错误）"
        except paramiko.SSHException as e:
            return None, f"SSH连接失败: {str(e)}"
        except Exception as e:
            return None, f"未知错误: {str(e)}"
        finally:
            client.close()

        # 匹配目标cron任务
        pattern = r"^\s*(\*|[\d,/-]+)\s+(\d+)\s+(\*|[\d,/-]+)\s+(\*|[\d,/-]+)\s+(\*|[\d,/-]+)\s+/usr/sbin/ntpdate\s+172\.16\.33\.26"

        for line in cron_content.splitlines():
            match = re.match(pattern, line)
            if match:
                return int(match.group(2)), None

        return None, "未找到匹配的cron任务"

    def get_sync_time(self, sync_time, url):
        # ssh连接S01-获取定时任务的时间
        result, error = self.get_cron_hour(url)
        parts = sync_time.split('=')
        match = re.search(r'(\d+)', parts[0])  # 匹配数字部分
        number = int(match.group(1))
        if result == number:
            self.logger.info('时间同步的定时任务时间和设置相同：%d',result)
        else:
            self.logger.error('时间同步的定时任务时间和设置不符')

    def set_system_time(self, base_url, new_time):
        """
        通过SSH连接设备并修改系统时间(支持重试机制)

        参数:
            base_url (str): 包含目标IP的URL（如 https://10.4.0.204:7443/login）
            new_time (str): 要设置的时间（格式：YYYY-MM-DD HH:MM:SS）

        返回:
            tuple: (结果, 错误信息)
            成功示例: (True, None)
            失败示例: (None, "连接失败: Connection refused (5次重试)")
        """
        # 解析URL获取IP
        try:
            parsed_url = urlparse(base_url)
            ip = parsed_url.hostname
            if not ip or not re.match(r"\d+\.\d+\.\d+\.\d+", ip):
                return None, "无效的IP地址"
        except Exception as e:
            return None, f"URL解析失败: {str(e)}"

        # SSH连接配置
        ssh_config = {
            "hostname": ip,
            "port": 22,
            "username": "root",
            "password": "Guoyu@657",
            "timeout": 10
        }

        max_retries = 5  # 最大重试次数
        retry_delay = 1  # 重试间隔(秒)

        for attempt in range(max_retries):
            client = None
            try:
                # 创建SSH客户端
                client = paramiko.SSHClient()
                client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

                # 带重试的连接
                client.connect(**ssh_config)

                # 执行时间修改命令
                command = f"date -s '{new_time}'"
                stdin, stdout, stderr = client.exec_command(command)
                exit_status = stdout.channel.recv_exit_status()

                # 检查命令执行结果
                if exit_status != 0:
                    error = stderr.read().decode().strip()
                    raise RuntimeError(f"命令执行失败 (code:{exit_status}): {error}")

                # 记录成功日志
                self.logger.info(f"时间修改成功： {new_time}")
                return True, None

            except paramiko.AuthenticationException as e:
                error_msg = "SSH认证失败（密码错误）"
                self.logger.error(error_msg)
                return None, error_msg  # 认证错误不重试
            except Exception as e:
                error_msg = f"尝试 {attempt + 1}/{max_retries} 失败: {str(e)}"
                self.logger.warning(error_msg)

                # 最后一次失败不等待
                if attempt < max_retries - 1:
                    time.sleep(retry_delay)
            finally:
                if client:
                    client.close()

        return None, f"连接失败: {str(e)} ({max_retries}次重试)"

    def get_local_time(self):
        """
        获取本机系统时间并格式化返回

        返回:
            tuple: (结果, 错误信息)
            成功示例: ("2024-05-20 12:34:56", None)
            失败示例: (None, "时间获取失败: 异常信息")
        """
        try:
            # 获取当前时间并格式化
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.logger.info(f"本机当前时间获取成功: {current_time}")
            return current_time
        except Exception as e:
            return None, self.logger.error(f"时间获取失败: {str(e)}")
